const { BaseCommand } = require("./base");

const fs = require("node:fs");
const path = require("node:path");
const { get_full_path, get_file_list } = require("../utils/file_tool");
const { info } = require("../utils/log_tool");
const { progress } = require("../utils/display_tool");

class FtpCommand extends BaseCommand {
    async execute() {
        const config = this.selfData.config;
        const mode = this.selfData.mode;
        return await new Promise((resolve, reject) => {
            var Client = require("ftp");
            var c = new Client();
            c.on("ready", () => {
                switch (mode) {
                    case "VIEW": {
                        const src = this.selfData.src || "/";
                        c.list(src, (err, list) => {
                            if (err) {
                                throw err;
                            }
                            resolve(list);
                            c.end();
                        });
                        break;
                    }
                    case "DOWNLOAD": {
                        const src = this.selfData.src;
                        const dst = get_full_path(this.selfData.dst);
                        const remote_dirname = path.dirname(src);
                        const remote_basename = path.basename(src);
                        c.list(remote_dirname, (err, list) => {
                            if (err) {
                                throw err;
                            }
                            const element = list.find(
                                (element) => element.name === remote_basename,
                            );
                            if (element) {
                                let cur = 0,
                                    total = element.size;
                                c.get(src, (err, stream) => {
                                    if (err) {
                                        throw err;
                                    }
                                    stream.on("data", (d) => {
                                        cur += d.length;
                                        progress(
                                            cur,
                                            total,
                                            {
                                                desc: `Downloading from ${src}`,
                                                depth: 0,
                                                color: "green",
                                                align: true,
                                                format_bytes: true,
                                            },
                                            true,
                                        );
                                    });
                                    stream.once("close", () => {
                                        c.end();
                                        resolve(true);
                                    });
                                    stream.pipe(fs.createWriteStream(dst));
                                });
                            } else {
                                reject(`Not found ${src}`);
                            }
                        });
                        break;
                    }
                    case "UPLOAD_FILE":
                    case "UPLOAD": {
                        const dst = this.selfData.dst;
                        const src = get_full_path(this.selfData.src);
                        let readStream = fs.createReadStream(src),
                            cur = 0,
                            total = fs.statSync(src).size;
                        readStream.on("data", (d) => {
                            cur += d.length;
                            progress(
                                cur,
                                total,
                                {
                                    desc: `Uploading to ${dst}`,
                                    depth: 0,
                                    color: "green",
                                    align: true,
                                    format_bytes: true,
                                },
                                true,
                            );
                        });
                        c.put(readStream, dst, (err) => {
                            if (err) {
                                throw err;
                            }
                            c.end();
                            resolve(true);
                        });
                        break;
                    }
                    case "UPLOAD_FILES": {
                        const dst_folder = this.selfData.dst_folder;
                        const srcs = get_file_list(
                            this.selfData.src,
                            undefined,
                            true,
                        );
                        const base = this.selfData.base;
                        const numFiles = srcs.length;
                        if (numFiles) {
                            let numComplete = 0;

                            function completeOne() {
                                ++numComplete;
                                if (numComplete === numFiles) {
                                    c.end();
                                    resolve(true);
                                }
                            }

                            for (let i = 0; i < numFiles; i++) {
                                const src = srcs[i];
                                const dst = path.join(
                                    dst_folder,
                                    path.relative(base, src),
                                );
                                let readStream = fs.createReadStream(src),
                                    cur = 0,
                                    total = fs.statSync(src).size;
                                readStream.on("data", (d) => {
                                    cur += d.length;
                                    const percentageComplete = (
                                        (cur / total) *
                                        100
                                    ).toFixed(1);
                                    progress(
                                        i + cur / total,
                                        numFiles,
                                        {
                                            desc: `Uploading to ${dst} [${percentageComplete}%]`,
                                            depth: 0,
                                            color: "green",
                                            align: true,
                                        },
                                        true,
                                    );
                                });
                                c.put(readStream, dst, (err) => {
                                    if (err) {
                                        throw err;
                                    }
                                    completeOne();
                                });
                            }
                        } else {
                            resolve(true);
                        }
                        break;
                    }
                    default: {
                        resolve(false);
                        break;
                    }
                }
            });
            // connect to localhost:21 as anonymous
            c.connect(config);
        });
    }
}

module.exports = {
    FtpCommand,
};
